import Dep from './dep'
import { isObject, def } from '../util/index'
import { arrayMethods } from './array'

/**
 * Observer 类会通过递归的方式把一个对象的所有属性都转化成可观测对象
 */
class Observe {
  constructor (value) {
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      value.__proto__ = arrayMethods
      this.observeArray(value)
    } else {
      this.walk(value)
    }
  }
  /* 数组检测 */
  observeArray (arr) {
    for (const value of arr.values()) {
      observe(value)
    }
  }
  /* 对象检测 */
  walk (obj) {
    const keys = Object.keys(obj)
    keys.forEach(key => {
      defineReactive(obj, key, obj[key])
    })
  }
}

/*
 * 使一个对象转化成可观测对象
 */
function defineReactive (data, key, value) {
  const dep = new Dep() // 实例化一个依赖管理器，生成一个依赖管理数组dep

  Object.defineProperty(data, key, {
    get () {
      if (Dep.target) {
        dep.depend()
      }
      return value
    },
    set (newValue) {
      if (newValue === value || (newValue !== newValue && value !== value)) return
      observe(newValue)
      value = newValue
      dep.notify()
    }
  })
}

/**
 * MVVM模式：数据变化可以驱动视图变化
 * @param data
 */
export function observe (data) {
  if (!isObject(data)) return
  return new Observe(data)
}
